package xyz.labmem.app.unit

import atlantafx.base.theme.Styles
import atlantafx.base.theme.Tweaks
import cn.hutool.core.convert.Convert
import cn.hutool.core.util.StrUtil
import javafx.animation.KeyFrame
import javafx.animation.KeyValue
import javafx.animation.Timeline
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleStringProperty
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.event.EventHandler
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.control.TableColumn
import javafx.scene.control.TableView
import javafx.scene.control.TextArea
import javafx.scene.control.TextField
import javafx.scene.image.ImageView
import javafx.scene.layout.*
import javafx.scene.paint.Color
import javafx.util.Callback
import javafx.util.Duration
import xyz.labmem.app.config.AppConfig.messageImage
import xyz.labmem.app.config.AppConfig.mouseImage
import xyz.labmem.app.config.AppConfig.uiImage
import xyz.labmem.app.dialog.DialogBtn
import xyz.labmem.app.dialog.FormDialog
import xyz.labmem.app.main.CenterPane
import xyz.labmem.app.main.MainStage
import xyz.labmem.common.property.ContextProperty.serverStatusProperty
import xyz.labmem.lipx.core.context.AppContext
import xyz.labmem.lipx.core.context.ServerContext
import xyz.labmem.lipx.core.entity.ClientData
import xyz.labmem.lipx.core.util.ServerConfigDataUtil
import xyz.labmem.util.viewRun

/**
 * @author       : ltty
 * @description  :
 * @createDate   : 2024/11/8
 */
class ServerUnit(parent: CenterPane) : StackPane() {

    private val form = VBox()

    private val status = VBox()

    private val view = HBox(form, status)

    private val statusImage = ImageView()
    private val sword: ImageView
    private val serverPort = TextField()
    private val serverPassword = TextField()
    private val wls = TextArea()
    private val auto = SwitchUnit()
    private val msg = MsgUnit.getMsgUnit()
    private var fail = false
    private var checkSwitch = SimpleBooleanProperty(false)

    init {
        prefHeightProperty().bind(parent.prefHeightProperty())
        prefWidthProperty().bind(parent.prefWidthProperty().subtract(230))
        val imageView = ImageView(uiImage["default"])
        imageView.isPreserveRatio = true
        imageView.opacity = .3
        imageView.fitHeightProperty().bind(parent.prefHeightProperty())
        children.addAll(imageView, view)
        form.prefWidth = 380.0
        status.prefHeightProperty().bind(parent.prefWidthProperty().subtract(380))
        statusImage.fitHeightProperty().bind(parent.prefHeightProperty().multiply(.4))
        statusImage.isPreserveRatio = true
        sword = ImageView(uiImage["sword"]).apply {
            rotate = 45.0
            isPreserveRatio = true
            fitHeightProperty().bind(statusImage.fitHeightProperty().multiply(.8))
            isVisible = false
        }
        status.children.addAll(
            Pane(statusImage, sword).apply {
                VBox.setMargin(this, Insets(10.0, 0.0, 20.0, 150.0))
                onMouseClicked = EventHandler {
                    MainStage.confirmDialog(
                        "Lipx Server",
                        if (!checkSwitch.value) "要启动服务吗？" else "要关闭服务吗？",
                    ) {
                        fail = false
                        MainStage.loadingView {
                            if (!checkSwitch.value)
                                try {
                                    AppContext.Server.cacheData?.let { AppContext.Server.server.start(it) }
                                } catch (e: Exception) {
                                    fail = true
                                    statusImage.image = messageImage["fail"]
                                }
                            else
                                AppContext.Server.server.close()
                            checkSwitch.value = !checkSwitch.value
                        }
                        true
                    }
                }
            }, createTable()
        )
        refresh()
        serverStatusProperty.addListen {
            if (it) {
                Thread {
                    Thread.sleep(500)
                    viewRun {
                        makeSword()
                        statusImage.image = messageImage["clear"]
                    }
                }.start()
            } else {
                sword.isVisible = false
                if (!fail)
                    statusImage.image = messageImage["default"]
            }
        }
    }

    fun refresh() {
        //获取配置
        ServerConfigDataUtil.refreshData()
        val serverConfig = AppContext.Server.cacheData
        form.children.clear()
        makeItem("服务端口", serverPort)
        makeItem("服务密码", serverPassword)
        makeItem("白名单", wls)
        wls.prefWidth = 194.0
        makeItem("自启动", auto)
        serverPort.text = serverConfig?.port.toString()
        serverPassword.text = serverConfig?.password
        wls.text = serverConfig?.wls?.joinToString(",")
        auto.valueProperty.value = serverConfig?.autoRun

        DialogBtn("保存配置", color = Color.web("#ffed07")) {
            verify()
        }.apply {
            VBox.setMargin(this, Insets(30.0, 5.0, 0.0, 100.0))
            form.children.add(this)
        }
        if (serverStatusProperty.value()) {
            statusImage.image = messageImage["clear"]
        } else
            statusImage.image = messageImage["default"]

        checkSwitch.value = serverStatusProperty.value()
    }


    //校验
    private fun verify() {
        listOf(serverPort, serverPassword, wls).forEach {
            it.pseudoClassStateChanged(Styles.STATE_DANGER, false)
        }
        //分组
        try {
            Convert.toInt(serverPort.text)
            if (serverPort.text.toInt() <= 0 || serverPort.text.toInt() > 65535) {
                msg.showMsg("服务端口 必须为1-65535 喵~")
                serverPort.pseudoClassStateChanged(Styles.STATE_DANGER, true)
                return
            }
        } catch (e: Exception) {
            msg.showMsg("服务端口 必须为正整数 喵~")
            serverPort.pseudoClassStateChanged(Styles.STATE_DANGER, true)
            return
        }
        if (StrUtil.isNotBlank(serverPassword.text) && (serverPassword.text.length < 4 || serverPassword.text.length > 32)) {
            msg.showMsg("密码 字符长度需在4-32位 喵~")
            serverPassword.pseudoClassStateChanged(Styles.STATE_DANGER, true)
            return
        }
        if (StrUtil.isNotBlank(wls.text)) {
            if (wls.text.length > 255) {
                msg.showMsg("白名单 字符长度不能超过255 喵~")
                wls.pseudoClassStateChanged(Styles.STATE_DANGER, true)
                return
            }
            try {
                HashSet(wls.text.split(","))
            } catch (i: Exception) {
                msg.showMsg("白名单 数组输入错误！示例: 127.0.0.1,127.0.0.2 喵~")
                wls.pseudoClassStateChanged(Styles.STATE_DANGER, true)
                return
            }
        }
        //save
        AppContext.Server.cacheData?.let {
            it.wls = if (StrUtil.isNotBlank(wls.text)) HashSet(wls.text.split(",")) else HashSet()
            it.port = serverPort.text.toInt()
            it.password = serverPassword.text
            it.autoRun = auto.valueProperty.value
            ServerConfigDataUtil.write(it)
            msg.showMsg("服务配置保存成功了 喵~")
        }
    }

    private fun makeItem(label: String, input: Region) {
        if (input !is SwitchUnit) {
            input.cursor = mouseImage["m5"]
            input.onMouseEntered = EventHandler {
                MainStage.setCursor(mouseImage["m5"])
                FormDialog.setCursor(mouseImage["m5"])
            }
            input.onMouseExited = EventHandler {
                MainStage.cursorBack()
                FormDialog.cursorBack()
            }
            HBox.setMargin(input, Insets(.0, .0, .0, 20.0))
        } else {
            HBox.setMargin(input, Insets(.0, 100.0, .0, 20.0))
        }
        form.children.add(HBox(LabelUnit(label, 22.0, rotateE = 5.0, rotateS = -5.0), input).apply {
            VBox.setMargin(this, Insets(25.0, 10.0, .0, .0))
            alignment = Pos.CENTER_RIGHT
        })
    }

    private fun makeSword() {
        sword.isVisible = true
        sword.layoutX = 350.0
        sword.layoutY = -100.0
        sword.translateX = .0
        Timeline(
            KeyFrame(Duration.millis(100.0), KeyValue(sword.layoutXProperty(), 270)),
            KeyFrame(Duration.millis(100.0), KeyValue(sword.layoutYProperty(), 20)),
        ).play()
    }

    private fun createTable(): TableView<ClientData> {
        val ttb = TableView<ClientData>().apply {
            prefWidthProperty().bind(
                this@ServerUnit.prefWidthProperty().subtract(390)
            )
            prefHeightProperty().bind(this@ServerUnit.prefHeightProperty().multiply(.55))
            styleClass.addAll(Tweaks.EDGE_TO_EDGE, Tweaks.ALT_ICON)
        }
        ttb.columns.setAll(
            TableColumn<ClientData, String>("连接时间").apply {
                cellValueFactory = Callback<TableColumn.CellDataFeatures<ClientData, String>, ObservableValue<String>> {
                    SimpleStringProperty(it.value.connectTime ?: "")
                }
                prefWidthProperty().bind(ttb.prefWidthProperty().multiply(.3))
                styleClass.addAll(Tweaks.ALIGN_CENTER)
            }, TableColumn<ClientData, String>("连接IP").apply {
                cellValueFactory = Callback<TableColumn.CellDataFeatures<ClientData, String>, ObservableValue<String>> {
                    SimpleStringProperty(it.value.ip ?: "")
                }
                prefWidthProperty().bind(ttb.prefWidthProperty().multiply(.2))
                styleClass.addAll(Tweaks.ALIGN_CENTER)
            }, TableColumn<ClientData, String>("连接名称").apply {
                cellValueFactory = Callback<TableColumn.CellDataFeatures<ClientData, String>, ObservableValue<String>> {
                    SimpleStringProperty(it.value.name ?: "")
                }
                prefWidthProperty().bind(ttb.prefWidthProperty().multiply(.18))
                styleClass.addAll(Tweaks.ALIGN_CENTER)
            }, TableColumn<ClientData, String>("使用端口").apply {
                cellValueFactory = Callback<TableColumn.CellDataFeatures<ClientData, String>, ObservableValue<String>> {
                    SimpleStringProperty(it.value.port?.toString() ?: "")
                }
                prefWidthProperty().bind(ttb.prefWidthProperty().multiply(.17))
                styleClass.addAll(Tweaks.ALIGN_CENTER)
            }, TableColumn<ClientData, String>("代理模式").apply {
                cellValueFactory = Callback<TableColumn.CellDataFeatures<ClientData, String>, ObservableValue<String>> {
                    SimpleStringProperty(if (it.value.isReceive) "正向代理" else "反向代理")
                }
                prefWidthProperty().bind(ttb.prefWidthProperty().multiply(.15))
                styleClass.addAll(Tweaks.ALIGN_CENTER)
            }
        )
        ServerContext.userList.addListener { _, _, v ->
            ttb.items = FXCollections.observableArrayList(v.values)
        }
        return ttb
    }
}